package com.mike.billingserver.service.impl;

import com.mike.billingserver.constant.ApplicationConstant;
import com.mike.billingserver.dto.BillSearchDTO;
import com.mike.billingserver.entity.Bill;
import com.mike.billingserver.entity.BillCategory;
import com.mike.billingserver.form.BillForm;
import com.mike.billingserver.repository.BillCategoryRepository;
import com.mike.billingserver.repository.BillRepository;
import com.mike.billingserver.service.BillService;
import com.mike.billingserver.vo.BillListVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xiaozefeng
 * @date 2018-12-19 10:22
 */
@Service
public class BillServiceImpl implements BillService {

    @Autowired
    private BillCategoryRepository billCategoryRepository;

    @Autowired
    private BillRepository billRepository;

    @Override
    public List<BillCategory> getBillCategories() {
        return billCategoryRepository.findAll();
    }

    @Override
    public BillForm createBill(BillForm billForm) {
        Bill bill = new Bill();
        bill.setPurpose(billForm.getUse());
        bill.setAmount(billForm.getAmount());
        bill.setCategoryId(billForm.getCategory());
        bill.setImgs("");
        bill.setLocation("");
        String happenedTimeStr = billForm.getHappenedTime();
        String inputHappenedTimeStr = billForm.getInputHappenedTime();
        LocalDate happenedTime = LocalDate.now();
        if (!StringUtils.isEmpty(inputHappenedTimeStr)) {
            happenedTime = LocalDate.parse(inputHappenedTimeStr, ApplicationConstant.DEFAULT_TIME_FORMATTER);
        }
        bill.setHappenedTime(happenedTime);
        bill.setYear(happenedTime.getYear());
        bill.setMonth(happenedTime.getMonthValue());
        bill.setDay(happenedTime.getDayOfMonth());
        billRepository.save(bill);
        billForm.setId(bill.getId());
        return billForm;
    }

    @Override
    public List<BillListVO> findAll() {
        List<Bill> bills = billRepository.findAll();
        return bills.stream()
                .map(this::convertBill).collect(Collectors.toList());
    }

    @Override
    public Page<BillListVO> findWithPage(Pageable pageable) {
        Page<Bill> billPage = billRepository.findAll(pageable);
        long count = billPage.getTotalElements();
        if (count == 0) {
            return new PageImpl<>(Collections.emptyList());
        }
        return billPage.map(this::convertBill);
    }

    @Override
    public Page<BillListVO> findAll(Pageable pageable, BillSearchDTO billSearchDTO) {
        final Integer year = billSearchDTO.getYear();
        final Integer month = billSearchDTO.getMonth();
        String purpose = billSearchDTO.getPurpose();
        Page<Bill> billPage = billRepository.findAll((Specification<Bill>) (root, cq, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("year"), year));
            predicates.add(cb.equal(root.get("month"), month));
            if (!StringUtils.isEmpty(purpose)) {
                predicates.add(cb.like(root.get("purpose"), "%" + purpose + "%"));
            }
            return cb.and(predicates.toArray(new Predicate[0]));
        }, pageable);
        return billPage.map(this::convertBill);
    }

    private BillListVO convertBill(Bill bill) {
        String categoryId = bill.getCategoryId();
        BillCategory category = billCategoryRepository.getOne(categoryId);
        BillListVO billListVO = new BillListVO();
        billListVO.setAmount(bill.getAmount().toString());
        billListVO.setPurpose(bill.getPurpose());
        billListVO.setCategory(category.getName());
        billListVO.setHappenedTime(bill.getHappenedTime().format(ApplicationConstant.DEFAULT_TIME_FORMATTER));
        billListVO.setCreatedBy(bill.getCreatedBy());
        return billListVO;
    }
}
